/*------------------------------------------------------------------------------

 Copyright 2007 Sony Corporation

------------------------------------------------------------------------------*/
/**
 @file    shell.c

          This file provides .

 @author  Luc Fourestier
 @version 0.1
 @date    03/2007

*/
/*----------------------------------------------------------------------------*/


/*------------------------------------------------------------------------------
 Includes
------------------------------------------------------------------------------*/

#include "types.h"
#include "assert.h"
#include "tx.h"
#include "libc.h"

#include "uart.h"
#include "dvbtest.h"

/* mandatory include file */
#include "shell.h"



/*------------------------------------------------------------------------------
 Defines
------------------------------------------------------------------------------*/

/* local echo */
#define ECHO

#define SHELL_OUT  uart_Write     /* function of the type func(char c) */
#define SHELL_IN   uart_Read      /* function of the type func(char *c, int wait) */

#define COMMAND_BUFFER_SIZE 80
#define MAX_ARG_NUMBER  16

/*------------------------------------------------------------------------------
 Globals
------------------------------------------------------------------------------*/

/*------------------------------------------------------------------------------
 Statics
------------------------------------------------------------------------------*/

static void ClearCommandBuffer(char * commandBuffer);
static void ParseCommandLine(char * commandBuffer);
static void ExecuteCommandLine(char ** argv, int argc);

static TX_MUTEX printProtectMut;

/*------------------------------------------------------------------------------
 Functions
------------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/**
 wait for inputs.
 treat the input.

 @param  initialValue = unused
 @return NONE
*/
/*----------------------------------------------------------------------------*/
void shell_Task(ULONG initialValue)
{
    char c = 0;
    int status = 1; /* OK */
    unsigned int ComBuffIndex = 0;
    char CommandBuffer[COMMAND_BUFFER_SIZE];

    /* Init */
    ClearCommandBuffer(CommandBuffer);

    tx_mutex_create(&printProtectMut, "PrintProtectMutex", TX_INHERIT);

    shell_PrintString("\r\nSHELL> ");

    /* main loop */
    while(1)
    {
        status = SHELL_IN(&c, TX_WAIT_FOREVER);
#ifdef ECHO
        SHELL_OUT(c);
#endif
        if (status) /* if OK */
        {
        	if (ComBuffIndex < COMMAND_BUFFER_SIZE) /* buffer not full */
        	{
                if ((c == '\n') || (c == '\r')) /* execute the command */
                {
                    shell_PrintString("\r\n");
                    CommandBuffer[ComBuffIndex] = 0;
                    ParseCommandLine(CommandBuffer);
                    ClearCommandBuffer(CommandBuffer);
                    ComBuffIndex = 0;
                    shell_PrintString("\r\nSHELL> ");
                }
                else if (c == 0x8)  /* backspace */
                {
                    if (ComBuffIndex > 0)
                    {
                        ComBuffIndex--;
                        CommandBuffer[ComBuffIndex] = 0;
                    }
                }
                else if ((c >= 32) && (c < 127)) /* alphanumerical codes */
                {
                	CommandBuffer[ComBuffIndex] = c;
                    ComBuffIndex++;
                }
                else
                {
                }
        	}
        	else
        	{
        	    CommandBuffer[COMMAND_BUFFER_SIZE-1] = 0;
        	    ParseCommandLine(CommandBuffer);
                ClearCommandBuffer(CommandBuffer);
                ComBuffIndex = 0;
                shell_PrintString("\r\nSHELL> ");
        	}
        }
    }
}



/*----------------------------------------------------------------------------*/
/**
 .

 @param  string = the string to print
 @return NONE
*/
/*----------------------------------------------------------------------------*/
void shell_PrintString(char * string)
{
    tx_mutex_get(&printProtectMut, TX_WAIT_FOREVER);

    while((*string) != 0)
    {
        SHELL_OUT(*string);
        string++;
    }

    tx_mutex_put(&printProtectMut);
}



/*----------------------------------------------------------------------------*/
/**
 .

 @param  integer = 32 bit integer
 @param  base = 10:decimal, 16:Hexdecimal (16 by default)
 @return NONE
*/
/*----------------------------------------------------------------------------*/
#define MAX_CHAR 11
void shell_PrintInteger(int integer, int base)
{
    char * code = "0123456789ABCDEF";
    char tempString[MAX_CHAR];
    int i = 0;
    int temp = 0;

    tempString[MAX_CHAR-1] = 0; /* NULL termination */

    tx_mutex_get(&printProtectMut, TX_WAIT_FOREVER);

    switch (base)
    {
    	case 10:
            i = MAX_CHAR - 1;
            do
            {
                tempString[i-1] = code[integer%10];
                integer = integer / 10;
                i--;
            }
            while((integer != 0) && (i != 0));

            while(i != (MAX_CHAR - 1))
            {
                SHELL_OUT(tempString[i]);
                i++;
            }
    		break;

    	case 16:
    	default:
            SHELL_OUT('0');
            SHELL_OUT('x');
            temp = 0;
            for (i=7; i>=0; i--)
            {
            	if ((integer >> (i*4)) & 0xF)
            	{
            		temp = 1;
            	}

            	if (temp) /* do not print the leading 0 */
            	{
                    SHELL_OUT(code[(integer >> (i*4)) & 0xF]);
            	}
            }
    		break;
    }

    tx_mutex_put(&printProtectMut);
}
#undef MAX_CHAR


/*----------------------------------------------------------------------------*/
/**
 S.

 @param  NONE
 @return NONE
*/
/*----------------------------------------------------------------------------*/
static void ClearCommandBuffer(char * commandBuffer)
{
    int i = 0;

    for (i=0; i<COMMAND_BUFFER_SIZE; i++)
    {
    	commandBuffer[i] = 0;
    }
}



/*----------------------------------------------------------------------------*/
/**
 S.

 @param  NONE
 @return NONE
*/
/*----------------------------------------------------------------------------*/
static void ParseCommandLine(char * commandBuffer)
{
    char * argv[MAX_ARG_NUMBER];
    int argc = 0;
    char c = 0;
    int i = 0;
    int newWord = 1;

    do
    {
    	c = commandBuffer[i];

    	if (c == 0)
    	{
            break;
    	}
        else if (c == 32)
        {
            commandBuffer[i] = 0; /* replace space by NULL */
            newWord = 1;
        }
        else
        {
            if (newWord == 1)
            {
                newWord = 0;

                argv[argc] = &commandBuffer[i];
                argc++;
                if (argc >= MAX_ARG_NUMBER)
                {
                    break;
                }
            }
        }

        i++;
    }
    while (c != 0);

    if (argc > 0)
    {
    	ExecuteCommandLine(argv, argc);
    }
}



/*----------------------------------------------------------------------------*/
/**
 S.

 @param  NONE
 @return NONE
*/
/*----------------------------------------------------------------------------*/
static void ExecuteCommandLine(char ** argv, int argc)
{
    char cmdId = *argv[0];
    int temp = 0;

    if (argc != 0)
    {
        switch (cmdId)
        {
            case 'c':
            case 'C':
                if (argc >= 2)
                {
                    temp = strtol(argv[1], 0, 10);
                    dvbtest_SetCommand((uint8_t) temp, &argv[2], (uint8_t)(argc-2));
                }
                else
                {
                    shell_PrintString("SHELL: invalid command line!\r\n");
                }
                break;
            case 'H':
            case 'h':
                shell_PrintString("HELP:\r\n");
                shell_PrintString("C or c     :Call dvbtest commands. (ex:C 1)\r\n");
                shell_PrintString("H or h     :Help.\r\n");
                break;

            default:
                shell_PrintString("SHELL: invalid command line!\r\n");
                break;
        }
    }
}


